package com.echo.im.repository.offline.support;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 分布式锁服务，提供获取锁、释放锁、续租等功能。
 *
 * 主要功能：
 * 1. 获取锁并设置 UUID (acquireLockWithUuid)
 * 2. 验证锁持有者 (isLockOwner)
 * 3. 释放锁并验证 UUID (releaseLockWithUuid)
 * 4. 锁的续租 (renewLock)
 *
 * @author echo
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class DistributedLockManager {

    private final RedissonClient redissonClient;

    /**
     * 获取锁并验证UUID，不等待
     *
     * @param lockKey 锁的键
     * @param uuid 唯一通用标识符
     * @param leaseTime 锁的租约时间
     * @param unit 时间单位
     * @return 如果成功获取锁并设置UUID，则为true；否则为false
     */
    public boolean acquireLockWithUuid(String lockKey, String uuid, long leaseTime, TimeUnit unit) {
        try {
            RLock lock = redissonClient.getLock(lockKey);
            if (lock.tryLock(0, leaseTime, unit)) {
                redissonClient.getBucket(lockKey + ":uuid")
                        .setAsync(uuid, leaseTime, unit)
                        .toCompletableFuture()
                        .join();
                return true;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("获取锁时被中断，key: {}", lockKey, e);
        } catch (Exception e) {
            log.error("获取锁时出错，key: {}", lockKey, e);
        }
        return false;
    }

    /**
     * 验证锁持有者是否为指定UUID
     *
     * @param lockKey 锁的键
     * @param uuid 唯一通用标识符
     * @return 如果当前锁持有者是指定的UUID，则返回true；否则返回false
     */
    public boolean isLockOwner(String lockKey, String uuid) {
        try {
            String storedUuid = (String) redissonClient.getBucket(lockKey + ":uuid").get();
            return uuid.equals(storedUuid);
        } catch (Exception e) {
            log.error("检查锁持有者时出错，key: {}", lockKey, e);
            return false;
        }
    }

    /**
     * 释放锁并验证UUID
     *
     * @param lockKey 锁的键
     * @param uuid 唯一通用标识符
     */
    public void releaseLockWithUuid(String lockKey, String uuid) {
        try {
            RLock lock = redissonClient.getLock(lockKey);
            String storedUuid = (String) redissonClient.getBucket(lockKey + ":uuid").get();
            if (uuid.equals(storedUuid)) {
                lock.unlock();
                redissonClient.getBucket(lockKey + ":uuid").delete();
            }
        } catch (Exception e) {
            log.error("释放锁时出错，key: {}, uuid: {}", lockKey, uuid, e);
        }
    }


    /**
     * 锁续租
     *
     * @param lockKey 锁的键
     * @param leaseTime 续租的时间
     * @param unit 时间单位
     */
    public void renewLock(String lockKey, long leaseTime, TimeUnit unit) {
        try {
            RLock lock = redissonClient.getLock(lockKey);
            if (lock.isHeldByCurrentThread()) {
                lock.lock(leaseTime, unit);
                boolean isExtended = redissonClient.getBucket(lockKey + ":uuid")
                        .expire(leaseTime, unit);
                log.info("续租锁成功，key: {}, leaseTime: {}, uuid过期时间更新: {}", lockKey, leaseTime, isExtended);
            } else {
                log.warn("续租锁失败，当前线程未持有锁，key: {}", lockKey);
            }
        } catch (Exception e) {
            log.error("续租锁时出错，key: {}", lockKey, e);
        }
    }
}

